﻿//
// © Algobox Ltd - Benn Eichhorn
//
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
using System.Collections.Concurrent;
using Algobox.Objects.Finance.Assets.Stock;
using Algobox.Objects.Finance;
using Algobox.Toolbox.Collections;
using Algobox.Structure.Finance.Strategies.SmartStoploss;
using System.Windows.Data;
using System.Collections.ObjectModel;

namespace Algobox.Structure.Finance.Strategies.Moss
{
    public class MossManagement
    {
        #region Constructors

        public MossManagement(Algobox.Feeds.Finance.MarketData.IMarketFeedAdaptor marketFeed,
            Algobox.Feeds.Finance.Trading.ITradingFeedAdaptor tradingFeed)
        {
            _marketFeed = marketFeed;
            _tradingFeed = tradingFeed;
        }

        #endregion
//////////////////
        #region Member Variables

        public readonly static TimeSpan TIME_BARS_START = TimeSpan.FromHours(8); // 08:00:00
        public readonly static TimeSpan TIME_LAST_ENTRY = TimeSpan.FromHours(16.27); // 16:16:12
        public readonly static TimeSpan TIME_EXIT_ALL = TimeSpan.FromHours(16.45); // 16:27:00

        /// <summary>
        /// Logger used by this class
        /// </summary>        
        private static readonly NLog.Logger Log = NLog.LogManager.GetCurrentClassLogger();
        
        private Algobox.Feeds.Finance.MarketData.IMarketFeedAdaptor _marketFeed;
        private Algobox.Feeds.Finance.Trading.ITradingFeedAdaptor _tradingFeed;
        
        #endregion
//////////////////
        #region Properties

        public bool IsLoaded { get; private set; }
        public bool IsStarted { get; private set; }

        public ConcurrentObservableDictionary<Guid, MossStock> Strategies { get; set; }
        public ConcurrentObservableDictionary<Strategy, StrategyUnitSummary> ViewUnitSummary { get; set; }
        public ListCollectionView ViewUnits { get; set; }

        #endregion
//////////////////
        #region Functions

        public MossStock AddOrUpdate(
            Guid id,
            StockSecurity security,
            string account,
            int unitValue,
            int rsiTop,
            int rsiBottom,
            int rsiRetrace,
            int bollyPeriod,
            double bollyStdDevs)
        {
            // save original settings in TerappinData struct

            // create the view if we are not using a base view created elsewhere
            if (Strategies == null)
            {
                Strategies = new ConcurrentObservableDictionary<Guid, MossStock>();
            }
            

            if (!security.Listings.ContainsKey(Exchanges.ExchangeMIC.BATE))
            {
                Log.Info("Failed to create MossStock {0} as couldn't not find a BATSEU listing",
                    security);
                return null;
            }

            Log.Info("Creating MossStock {0} with a UnitValue({1}), RSITop({2}), RSIBottom({3}), RSIRetrace({4}), BollyPeriod({5}), BollySTDEV({5})",
                security,
                unitValue,
                rsiTop,
                rsiBottom,
                rsiRetrace,
                bollyPeriod,
                bollyStdDevs);

            // create or update the strategy and add it to the manager dictionary
            MossStock strategy = Strategies.AddOrUpdate(id,
                (key) =>
                {
                    MossStock ms = new MossStock(this,
                        _tradingFeed,
                        security,
                        id,
                        account,
                        unitValue,
                        rsiTop,
                        rsiBottom,
                        rsiRetrace,
                        bollyPeriod,
                        bollyStdDevs);

                    _marketFeed.SubscribeLast(security, ms);
                    //_marketFeed.SubscribeBid(security, ms);
                    //_marketFeed.SubscribeAsk(security, ms);

                    return ms;
                },
                (key, inStrategy) =>
                {
                    if (id == inStrategy.DatabaseId)
                    {
                        inStrategy.UnitValue = unitValue;
                        inStrategy.RSITop = rsiTop;
                        inStrategy.RSIBottom = rsiBottom;
                        inStrategy.RSIRetrace = rsiRetrace;
                        inStrategy.BollyPeriod = bollyPeriod;
                        inStrategy.BollySTDEV = bollyStdDevs;
                    }                    
                    return inStrategy;
                });

            return strategy;
        }

        public void AddStrategyUnit(MossUnit unit)
        {
            ((ConcurrentObservableCollection<MossUnit>)ViewUnits.SourceCollection).Add(unit);

            StrategyUnitSummary summary = ViewUnitSummary.AddOrUpdate(unit.Strategy,
                (key) =>
                {
                    StrategyUnitSummary value = new StrategyUnitSummary(key, unit.Name);
                    _marketFeed.SubscribeLast(key.Security, value);
                    value.AddUnit(unit);
                    return value;
                },
                (key, value) =>
                {
                    value.AddUnit(unit);
                    return value;
                });
        }

        public void Remove(MossStock strategy)
        {
            _marketFeed.UnsubscribeLast(strategy.Security, strategy);
            //_marketFeed.UnsubscribeBid(strategy.Value.Security, strategy.Value);
            //_marketFeed.UnsubscribeAsk(strategy.Value.Security, strategy.Value);

            //strategy.ExitUnit(DateTime.Now);
            Strategies.TryRemove(strategy.DatabaseId);
        }

        public void RemoveAll()
        {
            foreach (KeyValuePair<Guid, MossStock> strategy in Strategies)
            {
                _marketFeed.UnsubscribeLast(strategy.Value.Security, strategy.Value);
                //_marketFeed.UnsubscribeBid(strategy.Value.Security, strategy.Value);
                //_marketFeed.UnsubscribeAsk(strategy.Value.Security, strategy.Value);
            }
            Strategies.Clear();
        }
        

        #endregion
//////////////////
        #region Enums


        #endregion

    }
}